package byx.container.annotation.extension.impl;

import byx.container.annotation.annotation.Value;
import byx.container.annotation.exception.StringConverterNotFoundException;
import byx.container.annotation.extension.core.ParameterHandler;
import byx.container.annotation.extension.core.ParameterInfo;
import byx.container.core.Container;
import byx.container.core.ObjectFactories;
import byx.container.core.ObjectFactory;
import byx.container.core.utils.ReflectUtils;

import java.lang.reflect.ParameterizedType;
import java.util.List;

public class ValueParameterHandler implements ParameterHandler {
    private final List<StringConverter<?>> converters;

    public ValueParameterHandler(List<StringConverter<?>> converters) {
        this.converters = converters;
    }

    @Override
    public boolean support(ParameterInfo param) {
        return param.getAnnotationMetadata().isAnnotationPresent(Value.class);
    }

    @Override
    public ObjectFactory<?> handle(ParameterInfo param, Container container) {
        StringConverter<?> converter = getConverter(param.getParameterType());
        return ObjectFactories.value(converter.convert(param.getAnnotationMetadata().getAnnotation(Value.class).value()));
    }

    private StringConverter<?> getConverter(Class<?> paramType) {
        try {
            for (StringConverter<?> converter : converters) {
                Class<?> type = (Class<?>) ((ParameterizedType) converter.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0];
                if (ReflectUtils.getWrap(paramType).isAssignableFrom(ReflectUtils.getWrap(type))) {
                    return converter;
                }
            }
        } catch (Exception e) {
            throw new StringConverterNotFoundException(paramType, e);
        }
        throw new StringConverterNotFoundException(paramType);
    }
}
